package com.mrjy.wechat.bo;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;

import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mrjy.common.dto.MiniProgramLoginDTO;
import com.mrjy.common.entity.DistributorInfo;
import com.mrjy.common.entity.UserInfo;
import com.mrjy.common.util.GlobalConstant;
import com.mrjy.maintain.dao.IUserInfoDao;
import com.mrjy.maintain.util.RoleInfoEnum;
import com.mrjy.maintain.util.SharingProportionEnum;
import com.mrjy.share.dao.IDistributorInfoDao;
import com.mrjy.wechat.conts.WxConsts;
import com.mrjy.wechat.process.AccessToken;
import com.mrjy.wechat.process.JSTicket;
import com.mrjy.wechat.util.ServletContextUtil;
import com.mrjy.wechat.util.WeChatUtil;

@Service("weChatOAuthBo")
public class WeChatOAuthBo implements IWeChatOAuthBo {

	private static Logger logger = Logger.getLogger(WeChatOAuthBo.class);  
	
	private static final byte[] tokenLock = new byte[0];
	private static final byte[] ticketLock = new byte[0];
	private static volatile AccessToken access_token;
	private static volatile JSTicket js_ticket;
	ServletContext sc =null;
//	static{
//		sc = ServletContextUtil.get();
//	}
	@Autowired
	private IUserInfoDao userInfoDao ;
	@Autowired
	private IDistributorInfoDao distributorInfoDao ;
	
	
	/**
	 * 获取服务号的AccessToken
	 */
	@Override
	public AccessToken getAccessToken(String appId, String appSecret) {
		clearAccessToken();
		synchronized(tokenLock) {//加锁，避免重复获取token
			if (access_token == null) {//在锁内多判断一次是否为空，防止阻塞在锁上的线程重复获取token
				String requestUrl = WxConsts.getWeChatApiURL(WxConsts.GET_ACCESS_TOKEN, appId , appSecret) ;
				JSONObject jsonObject = WeChatUtil.httpsRequest(requestUrl, WxConsts.HTTP_GET, null);
				 //如果请求成功
				if (null != jsonObject) {
					try {
						access_token = new AccessToken();
						access_token.setAccessToken(jsonObject.getString("access_token"));
						access_token.setExpiresIn(jsonObject.getInt("expires_in"));
						
						//全局缓存access_token
						if (sc == null) {
							sc = ServletContextUtil.get();
						}
						sc.removeAttribute(WxConsts.ACCESS_TOKEN);
						sc.setAttribute(WxConsts.ACCESS_TOKEN, access_token);
						
					} catch (JSONException e) {
						// 获取token失败
						access_token = null;
					}
				}
			}
		}
		return access_token;
	}
	/**
	 * 获取微信JS-SDK签名的ticket
	 */
	@Override
	public JSTicket getJsapiTicket(AccessToken accessToken) {
		clearJsApiTicket();
		synchronized(ticketLock) {//加锁，避免重复获取ticket
			if (js_ticket == null) {//在锁内多判断一次是否为空，防止阻塞在锁上的线程重复获取ticket
				//AccessToken accessToken = getAccessToken(WxConsts.APPID, WxConsts.APPSECRET);
				if (null != accessToken) {
					String requestUrl = WxConsts.getWeChatApiURL(WxConsts.GET_JSAPI_TICKET, accessToken.getAccessToken());
					JSONObject jsonObject = WeChatUtil.httpsRequest(requestUrl, WxConsts.HTTP_GET, null);
					if(jsonObject.has("errcode")){
						if("42001".equals(jsonObject.getString("errcode")) || "40014".equals(jsonObject.getString("errcode"))){//accessToken 超时
							//清除失效的accessToken
							clearAccessToken();
							//重新获取accessToken
							accessToken = getAccessToken(WxConsts.APPID, WxConsts.APPSECRET);
							requestUrl = WxConsts.getWeChatApiURL(WxConsts.GET_JSAPI_TICKET, accessToken.getAccessToken());
							jsonObject = WeChatUtil.httpsRequest(requestUrl, WxConsts.HTTP_GET, null);
						}
					}
					// 如果请求成功
					if (null != jsonObject) {
						try {
							js_ticket = new JSTicket();
							js_ticket.setTicket(jsonObject.getString("ticket"));
							js_ticket.setExpiresIn(jsonObject.getInt("expires_in"));
							//全局缓存js_ticket
							if (sc == null) {
								sc = ServletContextUtil.get();
							}
							sc.removeAttribute(WxConsts.JS_TICKET);
							sc.setAttribute(WxConsts.JS_TICKET, js_ticket);
							
						} catch (JSONException e) {
							// 获取ticket失败
							js_ticket = null;
						}
					}
				}else {
					
				}
				
			}
		}
		return js_ticket;
	}
	/**
	 * 清除access_token
	 */
	@Override
	public void clearAccessToken() {
		access_token = null ;
		
	}
	/**
	 * 清除js_ticket
	 */
	@Override
	public void clearJsApiTicket() {
		js_ticket = null;
	}
	
	/**
     * 微信js-sdk签名
     * @param url 当前网页的URL，必须和调用wxjs的页面地址相同并且是进行过ICP备案验证的可信域名，不包含#及其后面部分
     * @return 包含签名(key=signature)、随机字符串(key=noncestr)、时间戳(key=timestamp)、appid的Map对象
     */
	@Override
	public Map<String, String> jsSdkSign(String url ) {
		
		Map<String, String> map = new HashMap<String, String>();
		//从全局缓存获取accessToken
		AccessToken accessToken = WxConsts.getAccessToken();
		if (null  == accessToken) { // 如果缓存没有，则手动获取
			accessToken = this.getAccessToken(WxConsts.APPID, WxConsts.APPSECRET);
		}
		System.out.println("------------------------------------------------------------------>accessToken:" + accessToken.getAccessToken());
		//从全局缓存获取ticket
		JSTicket js_ticket = WxConsts.getJSTicket();
		if (null == js_ticket) {
			js_ticket = this.getJsapiTicket(accessToken);
		}
		//随机字符串
		String noncestr = UUID.randomUUID().toString();
		//时间戳
        String timestamp = Long.toString(System.currentTimeMillis() / 1000);
        
        //注意这里参数名必须全部小写，且必须有序
        String string1 = "jsapi_ticket=" + js_ticket.getTicket()
                  	   + "&noncestr=" + noncestr
                       + "&timestamp=" + timestamp
                       + "&url=" + url;
        System.out.println("=============wxJsSdkSignature-string1:" + string1);
        try {
        	//用哈希算法加密
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(string1.getBytes("UTF-8"));
            //签名
            String signature = WeChatUtil.byteToHex(crypt.digest());
            System.out.println("=============wxJsSdkSignature-signature:" + signature);
            map.put("signature", signature);
            map.put("noncestr", noncestr);
            map.put("timestamp", timestamp);
            //appid
            map.put("appId", WxConsts.APPID);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        
		return map;
	}
	@Override
	public Map<String , Object> miniOAuthLogin(Map<String, Object> para , HttpSession session) {
		Map<String , Object> map = new HashMap<String, Object>() ;
		if(para == null){
			map.put("err_code", "400") ;
			map.put("err_msg", "参数为空");
			return map;
		}
		JSONObject paraObj = JSONObject.fromObject(para) ;
		logger.debug("小程序para参数的值------------------------> "+ paraObj.toString());
		String code = paraObj.getString("code") ; 
		JSONObject userInfo = paraObj.getJSONObject("userInfo");
		JSONObject wxuserInfo =  userInfo.getJSONObject("userInfo");
		//组装 openId,unionId和session_key 的 url
        String url = WxConsts.getWeChatApiURL(WxConsts.JSCODE2SESSION, WxConsts.MINI_APPID,WxConsts.MINI_APPSECRET , code);
        JSONObject jobj = WeChatUtil.httpsRequest(url,WxConsts.HTTP_POST, null);
        logger.debug("小程序根据code获取openid和unionId：------------------------> "+ jobj.toString());
        if(!jobj.isNullObject()){
        	if( jobj.toString().contains("errcode")){
            	map.put("err_code", jobj.getString("errcode"));
            	map.put("err_msg", jobj.getString("errmsg")) ;
            }else{
            	String unionid = "";
            	String openid = "" ;
            	String session_key = "" ;
            	UserInfo ui = null ;
            	if(jobj.toString().contains("unionid")) unionid = jobj.getString("unionid") ;
            	if(jobj.toString().contains("openid")) openid = jobj.getString("openid") ;
            	if(jobj.toString().contains("session_key")) session_key = jobj.getString("session_key");
            	if(StringUtils.isNotBlank(unionid)){
            		ui = userInfoDao.queryByWUnionid(unionid);
            	}else{
            		ui = userInfoDao.queryByWxMiniOpenId(openid);
            	}
        		if(ui == null){
        			String sex = "";
        			ui = new UserInfo() ;
        			if(!wxuserInfo.isNullObject()){
        				int gender = (int) wxuserInfo.get("gender");
        				switch(gender){
        					case 0: sex = "未知";
        							break;
        					case 1: sex = "男";
        							break;
        					case 2: sex = "女";
        							break;
        				}
        				ui.setProvince(wxuserInfo.getString("province"));
            			ui.setUserName(wxuserInfo.getString("nickName"));
            			ui.setCity(wxuserInfo.getString("city"));
            			ui.setHeadImgUrl(wxuserInfo.getString("avatarUrl"));
        			}
        			ui.setSex(sex);
        			ui.setRegisterDate(new Date().getTime());
        			ui.setDisableFlag(0);
        			ui.setRoleId(RoleInfoEnum.STUDENT.getRoleId());
        			ui.setWeixinUnionid(unionid);
        			ui.setMiniOpenid(openid);
        			ui.setSessionKey(session_key);
        			ui.setRecommendCode(userInfoDao.generateRecommendCodeOne(8));
        			
        			//设置sessionId
        			ui.setSessionId(session.getId());
        			
                    int result = userInfoDao.insert(ui);
                    if(result == 1){
                    	//插入推广者表
                    	DistributorInfo dInfo = new DistributorInfo();
                    	dInfo.setUserId(ui.getId());
                    	dInfo.setDistributorName(ui.getUserName());
                    	dInfo.setCreateTime(new Timestamp(ui.getRegisterDate()));
                    	dInfo.setShareCode(ui.getRecommendCode());
                    	dInfo.setDistributorType(SharingProportionEnum.NORMAL.getDistributorType());
                    	dInfo.setSharingProportion(SharingProportionEnum.NORMAL.getSharingProportion());
                    	dInfo.setDisabledFlag(0);
                    	distributorInfoDao.insert(dInfo);
                    }
        		}else{
        			ui.setWeixinUnionid(unionid);
        			ui.setMiniOpenid(openid);
        			ui.setSessionKey(session_key);
        			if(!wxuserInfo.isNullObject()){
        				ui.setHeadImgUrl(wxuserInfo.getString("avatarUrl"));
        			}
        			//设置sessionId
        			ui.setSessionId(session.getId());
        			
        			userInfoDao.updateById(ui);
        		}
        		//设置缓存到会话中
        		session.setAttribute(GlobalConstant.USER_INFO, ui);
        		
        		MiniProgramLoginDTO mini = new MiniProgramLoginDTO();
            	mini.setUserId(ui.getId());
            	mini.setMiniOpenid(openid);
            	mini.setSessionId(ui.getSessionId());
            	mini.setUserName(ui.getUserName());
            	mini.setMobilePhone(ui.getMobilePhone());
            	
            	map.put("err_code", "200") ;
            	map.put("err_msg", "登录成功");
            	map.put("data", mini);
            }
        	
        }else{
        	map.put("err_code", "500");
        	map.put("err_msg", "请求失败") ;
        }
        
		return map;
	}
	
	@Override
	public Object connectSession(Integer userId) {
		return userInfoDao.queryById(userId);
	}
	
}
